package com.we.tickets.service.Impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.we.tickets.contracts.ticketing.TicketingManagement;
import com.we.tickets.dao.*;
import com.we.tickets.service.TicketingService;
import com.we.tickets.util.CommonUtil;
import com.we.tickets.util.constants.Contracts;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.tuples.generated.Tuple4;
import org.web3j.tuples.generated.Tuple5;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.tx.gas.StaticGasProvider;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

@Service
public class TicketingServiceImpl implements TicketingService {
    @Autowired
    private Web3j web3j;

    @Autowired
    private UserDao userDao;

    @Autowired
    private TicketDao ticketDao;

    @Autowired
    private EventDao eventDao;

    @Autowired
    private ResaleQueueDao resaleQueueDao;

    @Autowired
    private TicketingNoticeDao ticketingNoticeDao;

    @Override
    public JSONObject mintTickets(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        JSONArray tickets = jsonObject.getJSONArray("buyTickets");
        List<JSONObject> msg = new ArrayList<>();
        for (int i = 0; i < tickets.size(); i++) {
            JSONObject ticket = tickets.getJSONObject(i);
            TransactionReceipt tr;
            try {
                tr = ticketingManagement.mintLIFE(
                        ticket.getBigInteger("ticketId"),
                        ticket.getObject("granteeList", TypeReference.LIST_STRING)
                ).sendAsync().get();
            } catch (Exception e) {
                e.printStackTrace();
                return CommonUtil.errorJson("操作失败");
            }
            List<TicketingManagement.ResellSuccessEventResponse> event = ticketingManagement.getResellSuccessEvents(tr);
            if (event.size() > 0) {

            }
        }

        return CommonUtil.successJson();
    }

    @Override
    public JSONObject resellTicket(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        TransactionReceipt tr;
        try {
            tr = ticketingManagement.resellLIFE(jsonObject.getBigInteger("LIFEId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        List<TicketingManagement.GetQueueNumEventResponse> event = ticketingManagement.getGetQueueNumEvents(tr);
        BigInteger num = event.get(0).num;
        jsonObject.put("num", num);
        resaleQueueDao.addQueueInfo(jsonObject);
        return CommonUtil.successJson(num);
    }

    @Override
    public JSONObject cancelReselling(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        JSONObject info = resaleQueueDao.getQueueInfo(jsonObject);
        try {
            ticketingManagement.cancelReselling(info.getBigInteger("ticketId"), info.getBigInteger("num")).sendAsync().get();
            resaleQueueDao.deleteQueueInfo(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }

        return CommonUtil.successJson();
    }

    @Override
    public JSONObject returnTicket(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        try {
            ticketingManagement.returnLIFE(jsonObject.getBigInteger("LIFEId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }

        return CommonUtil.successJson();
    }

    @Override
    public JSONObject grantTicket(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        try {
            ticketingManagement.grantLIFE(jsonObject.getBigInteger("LIFEId"), jsonObject.getString("toAddress")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        JSONObject notice = new JSONObject();
        notice.put("type", "grant");
        notice.put("from", jsonObject.getInteger("userId"));
        notice.put("fromUsername", jsonObject.getString("username"));
        notice.put("to", jsonObject.getInteger("toId"));
        notice.put("ticketId", jsonObject.getInteger("ticketId"));
        notice.put("LIFEId", jsonObject.getBigInteger("LIFEId"));
        notice.put("ticketName", jsonObject.getString("ticketName"));
        notice.put("eventTitle", jsonObject.getString("eventTitle"));
        notice.put("eventId", jsonObject.getInteger("eventId"));
        ticketingNoticeDao.addNotice(notice);

        return CommonUtil.successJson();
    }

    @Override
    public JSONObject cancelGranting(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        try {
            ticketingManagement.cancelGranting(jsonObject.getBigInteger("LIFEId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        ticketingNoticeDao.deleteNotice(jsonObject.getInteger("LIFEId"));
        return CommonUtil.successJson();
    }

    @Override
    public JSONObject acceptTicket(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("from"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        try {
            ticketingManagement.acceptLIFE(jsonObject.getBigInteger("LIFEId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        jsonObject.put("type", "acceptGranting");
        ticketingNoticeDao.granteeReactNotice(jsonObject);

        return CommonUtil.successJson();
    }

    @Override
    public JSONObject refuseTicket(JSONObject jsonObject) {
        jsonObject.put("type", "refuseGranting");
        ticketingNoticeDao.granteeReactNotice(jsonObject);
        return CommonUtil.successJson();
    }

    @Override
    public JSONObject checkIn(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        try {
            ticketingManagement.checkIn(jsonObject.getBigInteger("LIFEId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }

        return CommonUtil.successJson();
    }

    @Override
    public JSONObject getBuyableTicketsNum(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        BigInteger num;
        try {
            num = ticketingManagement.getBuyableTicketsNum(jsonObject.getBigInteger("ticketId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        return CommonUtil.successJson(num);
    }

    @Override
    public JSONObject getSoldTicketsNum(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        BigInteger num;
        try {
            num = ticketingManagement.getSoldTicketsNum(jsonObject.getBigInteger("ticketId")).sendAsync().get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        return CommonUtil.successJson(num);
    }

    @Override
    public JSONObject getLIFEInfo(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        Tuple4<BigInteger, Boolean, Boolean, Boolean> LIFEInfo;
        try {
            LIFEInfo = ticketingManagement.LIFEInfoMap(jsonObject.getBigInteger("LIFEId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        JSONObject res = new JSONObject();
        res.put("ticketId", LIFEInfo.component1());
        res.put("used", LIFEInfo.component2());
        res.put("toBeResold", LIFEInfo.component3());
        res.put("toBeAccepted", LIFEInfo.component4());
        return CommonUtil.successJson(res);
    }

    @Override
    public JSONObject getTicketsByOwnerId(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        return null;
    }

    @Override
    public JSONObject getLIFEsOfOwner(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        Tuple5<List<BigInteger>, List<BigInteger>, List<Boolean>, List<Boolean>, List<Boolean>> LIFEs;
        try {
            LIFEs = ticketingManagement.getLIFEsOfOwner().sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        List<JSONObject> res = new ArrayList<JSONObject>();
        int len = LIFEs.component1().size();
        for (int i = 0; i < len; i++) {
            JSONObject temp1 = new JSONObject();
            temp1.put("id", LIFEs.component2().get(i));
            JSONObject ticket = ticketDao.getTicketById(temp1);
            JSONObject temp2 = new JSONObject();
            temp2.put("id", ticket.getBigInteger("event_id"));
            JSONObject event = eventDao.getEventBasicInfo(temp2);
            String newJS = (event.toJSONString() + ticket.toJSONString()).replace("}{", ",");
            JSONObject resi = JSONObject.parseObject(newJS);
            resi.put("LIFEId", LIFEs.component1().get(i));
            resi.put("ticketId", LIFEs.component2().get(i));
            resi.put("used", LIFEs.component3().get(i));
            resi.put("toBeResold", LIFEs.component4().get(i));
            resi.put("toBeAccepted", LIFEs.component5().get(i));
            res.add(resi);
        }

        return CommonUtil.successJson(res);
    }

    @Override
    public JSONObject getGranteeList(JSONObject jsonObject) {
        TicketingManagement ticketingManagement;
        try {
            ticketingManagement = _getTicketingManagement(jsonObject.getInteger("userId"));
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        List granteeList;
        List<JSONObject> users = new ArrayList<>();
        try {
            granteeList = ticketingManagement.getGranteeList(jsonObject.getBigInteger("LIFEId")).sendAsync().get();
        } catch (Exception e) {
            e.printStackTrace();
            return CommonUtil.errorJson("操作失败");
        }
        for (int i = 0; i < granteeList.size(); i++) {
            Object grantee = granteeList.get(i);
            JSONObject user = userDao.getUserInfoByAddress((String) grantee);
            users.add(user);
        }
        return CommonUtil.successJson(users);
    }

    @Override
    public JSONObject getNotices(JSONObject jsonObject) {
        List<JSONObject> notices = ticketingNoticeDao.getNoticesOfUser(jsonObject);
        return CommonUtil.successJson(notices);
    }

    @Override
    public JSONObject deleteNotice(JSONObject jsonObject) {
        ticketingNoticeDao.deleteNotice(jsonObject.getInteger("LIFEId"));
        return CommonUtil.successJson();
    }

    @NotNull
    private TicketingManagement _getTicketingManagement(int id) throws InterruptedException, ExecutionException {
        String privateKey = userDao.getUserPrivateKeyById(id);
        Credentials credentials = Credentials.create(privateKey);
        ContractGasProvider contractGasProvider = new StaticGasProvider(BigInteger.valueOf(20000000000L), BigInteger.valueOf(6721975L));
        TicketingManagement ticketingManagement = TicketingManagement.load(Contracts.TicketingManagement ,web3j, credentials, contractGasProvider);
        return ticketingManagement;
    }
}
